package club.kingyin.easycache.component.annotation.handler;

import club.kingyin.easycache.cache.AbstractCache;
import club.kingyin.easycache.component.PostProcess;
import club.kingyin.easycache.component.annotation.InvokeHandler;
import club.kingyin.easycache.exception.InitException;
import club.kingyin.easycache.key.EasyCacheKey;
import club.kingyin.easycache.key.InvokePostProcess;
import club.kingyin.easycache.method.CacheMethod;
import club.kingyin.easycache.proxy.ProxyCacheInvokePostProcess;
import club.kingyin.easycache.proxy.ProxyKeyPostProcess;
import club.kingyin.easycache.utils.InstanceUtils;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.InvocationTargetException;

// 建议实现ProxyCacheInvokePostProcess接口的处理器
@Slf4j
public class AnnotationCacheMethodInvokeCustomizationPostProcess implements ProxyKeyPostProcess, ProxyCacheInvokePostProcess {

    @Override
    public boolean getCacheInterceptor(boolean pre, CacheMethod target,EasyCacheKey key) {
        if (target.getMethod().isAnnotationPresent(InvokeHandler.class)) {
            InvokeHandler handler = target.getMethod().getDeclaredAnnotation(InvokeHandler.class);
            try {
                ProxyCacheInvokePostProcess process = (ProxyCacheInvokePostProcess) PostProcessFactory.acpps.getOrDefault(handler.value(), (ProxyCacheInvokePostProcess) InstanceUtils.newInstance(handler.value()));
                log.debug("模块：[{}] 方法：[{}] 装载InvokeHandler {}", key.getModule(), key.getMethodName(), handler);
                if (handler.overall()) {
                    PostProcessFactory.overall.add(process);
                    for (PostProcess postProcess : PostProcessFactory.overall) {
                        if (postProcess instanceof ProxyCacheInvokePostProcess)
                            pre = ((ProxyCacheInvokePostProcess) postProcess).getCacheInterceptor(pre, target,key);
                    }
                    return pre;
                } else {
                    return process.getCacheInterceptor(pre, target, key);
                }
            } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | InstantiationException e) {
                // 初始化实例失败
                throw new InitException(e);
            }
        }
        return pre;
    }

    @Override
    public void postProcessBeforeEasyCacheKey(CacheMethod target) {
        if (target.getMethod().isAnnotationPresent(InvokeHandler.class)) {
            InvokeHandler handler = target.getMethod().getDeclaredAnnotation(InvokeHandler.class);
            try {
                InvokePostProcess<CacheMethod> process = (ProxyCacheInvokePostProcess) PostProcessFactory.acpps.getOrDefault(handler.value(), (ProxyCacheInvokePostProcess) InstanceUtils.newInstance(handler.value()));
                if (handler.overall()) {
                    PostProcessFactory.overall.add(process);
                    for (PostProcess postProcess : PostProcessFactory.overall) {
                        if (postProcess instanceof ProxyCacheInvokePostProcess)
                            ((ProxyCacheInvokePostProcess) postProcess).postProcessBeforeEasyCacheKey(target);
                    }
                } else {
                    process.postProcessBeforeEasyCacheKey(target);
                }
            } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | InstantiationException e) {
                // 初始化实例失败
                throw new InitException(e);
            }
        }
    }

    @Override
    public EasyCacheKey postProcessAfterEasyCacheKey(CacheMethod target, EasyCacheKey key) {
        if (target.getMethod().isAnnotationPresent(InvokeHandler.class)) {
            InvokeHandler handler = target.getMethod().getDeclaredAnnotation(InvokeHandler.class);
            try {
                InvokePostProcess<CacheMethod> process = (ProxyCacheInvokePostProcess) PostProcessFactory.acpps.getOrDefault(handler.value(), (ProxyCacheInvokePostProcess) InstanceUtils.newInstance(handler.value()));
                if (handler.overall()) {
                    PostProcessFactory.overall.add(process);
                    for (PostProcess postProcess : PostProcessFactory.overall) {
                        if (postProcess instanceof ProxyCacheInvokePostProcess)
                            key = ((ProxyCacheInvokePostProcess) postProcess).postProcessAfterEasyCacheKey(target,key);
                    }
                    return key;
                } else {
                    return process.postProcessAfterEasyCacheKey(target,key);
                }
            } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | InstantiationException e) {
                // 初始化实例失败
                throw new InitException(e);
            }
        }
        return key;
    }

    @Override
    public void postProcessAfterGetCache(CacheMethod target, AbstractCache cache, Object res, EasyCacheKey key) {
        if (target.getMethod().isAnnotationPresent(InvokeHandler.class)) {
            InvokeHandler handler = target.getMethod().getDeclaredAnnotation(InvokeHandler.class);
            try {
                ProxyCacheInvokePostProcess process = (ProxyCacheInvokePostProcess) PostProcessFactory.acpps.getOrDefault(handler.value(), (ProxyCacheInvokePostProcess) InstanceUtils.newInstance(handler.value()));
                if (handler.overall()) {
                    PostProcessFactory.overall.add(process);
                    for (PostProcess postProcess : PostProcessFactory.overall) {
                        if (postProcess instanceof ProxyCacheInvokePostProcess)
                            ((ProxyCacheInvokePostProcess) postProcess).postProcessAfterGetCache(target, cache, res, key);
                    }
                } else {
                    process.postProcessAfterGetCache(target, cache, res, key);
                }
            } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | InstantiationException e) {
                // 初始化实例失败
                throw new InitException(e);
            }
        }
    }
}
